package com.stx.Filter;

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.stx.common.Constants;
import com.stx.common.JwtUtils;
import com.stx.common.Result;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
@WebFilter(urlPatterns = "/*")
public class LoginCheckedFilter implements Filter {

    @Autowired
    private HandlerExceptionResolver handlerExceptionResolver;

    private final JwtUtils jwtUtils = new JwtUtils();
    private static final Logger logger = LogManager.getLogger(LoginCheckedFilter.class);

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // 处理CORS预检请求
        if (request.getMethod().equalsIgnoreCase(RequestMethod.OPTIONS.name())) {
            handleCorsPreflight(request, response);
            return;
        }

        String url = request.getRequestURI();

        // 检查是否是静态资源或需要放行的URL
        if (isExcludedUrl(url)) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        // 获取并解析JWT令牌
        String jwt = parseJwt(request);
        if (jwt == null || !validateJwt(jwt, request, response)) {
            sendNotLoggedInResponse(response);
            return;
        }

        filterChain.doFilter(servletRequest, servletResponse);
    }

    private boolean isExcludedUrl(String url) {
        boolean isExcluded =
                url.contains("login") ||
                        url.contains("chat") ||
                        url.contains("upload") ||
                        url.contains("file") ||
                        url.contains(Constants.AVATAR_PATH) ||
                        url.endsWith(".html") ||
                        url.endsWith(".js") ||
                        url.endsWith(".css") ||
                        url.equals("/") ||
                        url.endsWith(".woff") ||
                        url.endsWith(".ttf") ||
                        url.endsWith(".js.map") ||
                        url.startsWith("/img/") ||
                        url.contains("/swagger-ui.html") ||
                        url.contains("/doc.html") ||
                        url.endsWith(".mp3") ||
                        url.startsWith("/v3/") ||
                        url.equals("/favicon.ico") ||
                        url.equals("/swagger-resources");

        if (isExcluded) {
            logger.info("Excluding URL: {}", url);
        } else {
            logger.info("Not excluding URL: {}", url);
        }
        return isExcluded;
    }

    private String parseJwt(HttpServletRequest request) {
        String headerAuth = request.getHeader("Authorization");
        if (headerAuth != null && headerAuth.startsWith("Bearer ")) {
            return headerAuth.substring(7);
        }
        return null;
    }

    private boolean validateJwt(String jwt, HttpServletRequest request, HttpServletResponse response) {
        try {
            DecodedJWT verify = jwtUtils.verify(jwt);
            Integer userId = jwtUtils.getIntValue(verify, "userId");
            request.setAttribute("userId", userId);
            String nickName = jwtUtils.getStringValue(verify, "nickName");
            request.setAttribute("nickName", nickName);
            return true;
        } catch (Exception e) {
            logger.error("Failed to validate JWT: ", e);
            RuntimeException re = new RuntimeException("Invalid JWT token");
            handlerExceptionResolver.resolveException(request, response, null, re);
            return false;
        }
    }

    private void handleCorsPreflight(HttpServletRequest request, HttpServletResponse response) {
        response.setHeader("Access-Control-Allow-Origin", "*"); // 或者特定的源
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Requested-With");
        response.setStatus(HttpServletResponse.SC_OK);
    }

    private void sendNotLoggedInResponse(HttpServletResponse response) throws IOException {
        Result notLogin = Result.error("NOT_LOGIN");
        String jsonString = JSONObject.toJSONString(notLogin);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(jsonString);
    }
}